/** Copyright 2012 Google Inc. All Rights Reserved
 *  Author: rptoffender@google.com (Ryan Trinder)
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include <ctype.h>
#include <mntent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>

int
check_mounts (char *ft_name, char *ft_dir, char *ft_type, char *mt_name,
	      char *mt_dir, char *mt_type, char *type)
{
  if (((strcmp (ft_type, type)) == 0) && (strcmp (mt_type, type) == 0))
    {
      if (((strcmp (ft_name, mt_name)) == 0)
	  && (strcmp (ft_dir, mt_dir) == 0))
	{
	  return (EXIT_SUCCESS);
	}
    }

  return (EXIT_FAILURE);
}

int
mnt_cnt (char *fs_type)
{
  FILE *ft = setmntent ("/etc/fstab", "r");
  FILE *mt = setmntent ("/etc/mtab", "r");
  int mounted = 0;
  struct mntent *f;
  struct mntent *m;

  while ((f = getmntent (ft)))
    {
      while ((m = getmntent (mt)))
	{
	  if (check_mounts
	      (f->mnt_fsname, f->mnt_dir, f->mnt_type, m->mnt_fsname,
	       m->mnt_dir, m->mnt_type, fs_type) == EXIT_SUCCESS)
	    {
	      mounted++;
	    }
	}
    }

  endmntent (ft);
  endmntent (mt);
  return (mounted);
}

int
chk (char *fs_type, int cl_mnt, bool nag_mode)
{
  if (nag_mode == true)
    {

      if (mnt_cnt (fs_type) == cl_mnt)
	{
	  fprintf (stdout, "OK: %s Mounts: %d/%d\n", fs_type,
		   mnt_cnt (fs_type), cl_mnt);
	  return 0;
	}
      else if (mnt_cnt (fs_type) > cl_mnt)
	{
	  fprintf (stderr, "Err, I counted %d, you gave me %d\n",
		   mnt_cnt (fs_type), cl_mnt);
	  return 3;
	}
      else
	{
	  fprintf (stdout, "Warning: %s mounts: %d/%d found\n", fs_type,
		   mnt_cnt (fs_type), cl_mnt);
	  return 1;
	}
    }
  else
    {
      fprintf (stdout, "%d/%d %s mounts found\n", mnt_cnt (fs_type), cl_mnt,
	       fs_type);
    }
}

int
usage (int status)
{
  if (status == EXIT_SUCCESS)
    fprintf (stderr, "WTF");
  else
    {
      fprintf
	(stdout,
	 "Usage: -c <number of mounts to check> -t <file system type, eg: ext3, ext4, nfs, fuse.s3fs> -n <nagios mode> (Returns nagios values for OK, Warn, Crit) \n");
    }

  return (status);
}

int
main (int argc, char *argv[])
{
  char *fs_type;
  int opt;
  int cl_mnt;
  bool nag_mode = false;

  while ((opt = getopt_long (argc, argv, "c:t:n")) != -1)
    switch (opt)
      {
      case 'c':
	cl_mnt = atoi (optarg);
	break;
      case 't':
	fs_type = optarg;
	break;
      case 'n':
	nag_mode = true;
	break;
      case '?':
	if (optopt == 'c')
	  fprintf (stderr, "Option -%c requires an argument.\n", optopt);
	else if (optopt == 't')
	  fprintf (stderr, "Option -%c requires an argument.\n", optopt);
	else if (isprint (optopt))
	  fprintf (stderr, "Unknown option `%-c'.\n", optopt);
	return 1;
      default:
	usage (EXIT_FAILURE);
	break;
      }
  if (argc == 1)
    usage (EXIT_FAILURE);
  else
    {
      chk (fs_type, cl_mnt, nag_mode);
    }

  exit (EXIT_SUCCESS);
}
